package archforce.atp.x.ui.frame.component;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author wx
 * @version 1.0
 * @date 2022/4/8 16:43
 */
public class FacedComponent<T extends AbstractRowItemComponent<D>, D> extends JPanel{

    private final List<RowPanel<T,D>> rowPanelList = new ArrayList<>();

    private final JButton addBtn = new JButton("                                              新增                                              ");
    private final ButtonGroup buttonGroup = new ButtonGroup();

    private Class<? extends AbstractRowItemComponent<D>> rowItemType;

    private FacedComponent(Class<? extends AbstractRowItemComponent<D>> rowItemType){
        this(Collections.EMPTY_LIST, rowItemType);
    }

    private FacedComponent(List<D> bindRowData, Class<? extends AbstractRowItemComponent<D>> rowItemType) {
        super();
        init(bindRowData, rowItemType);
    }

    private void init(List<D> bindRowData, Class<? extends AbstractRowItemComponent<D>> rowItemType){
        this.rowItemType = rowItemType;
        if(bindRowData == null || bindRowData.isEmpty()){
            RowPanel<T, D> rowPanel = new RowPanel<>(0, buttonGroup, rowItemType);
            rowPanel.setRelatedPanel(this);
            this.rowPanelList.add(rowPanel);
        }else {
            for (int i = 0; i < bindRowData.size(); i++) {
                RowPanel<T, D> rowPanel = new RowPanel<>(i, buttonGroup, bindRowData.get(i), rowItemType);
                rowPanel.setRelatedPanel(this);
                this.rowPanelList.add(rowPanel);
            }
        }
        FlowLayout flowLayout = new FlowLayout();
        flowLayout.setAlignment(FlowLayout.CENTER);
        setLayout(flowLayout);
        addToPanel();
    }

    public static <T extends AbstractRowItemComponent<D>, D> FacedComponent<T,D> getInstance(Class<T> rowItemType){
        return new FacedComponent<>(rowItemType);
    }

    public static <T extends AbstractRowItemComponent<D>, D> FacedComponent<T, D> getInstance(Class<T> rowItemType, List<D> bindRowData){
        return new FacedComponent<>(bindRowData, rowItemType);
    }

    public void addRow(Integer index, D rowDataModel){
        RowPanel<T, D> rowPanel = new RowPanel<>(index, buttonGroup, rowDataModel, rowItemType);
        rowPanel.setRelatedPanel(this);
        addRow(rowPanel, index);
    }

    public void addRow(Integer index){
        RowPanel<T, D> rowPanel = new RowPanel<>(index, buttonGroup, rowItemType);
        rowPanel.setRelatedPanel(this);
        addRow(rowPanel, index);
    }

    public void addRow(RowPanel<T, D> rowPanel, Integer index){
        this.rowPanelList.add(index, rowPanel);
        ActionListener[] existListener = null;
        for (int i = 0; i < this.rowPanelList.size(); i++) {
            this.rowPanelList.get(i).setId(i);
            ActionListener[] temp = this.rowPanelList.get(i).getActionListeners();
            if(temp !=null && temp.length > 0){
                existListener = temp;
            }
        }
        if(existListener != null) {
            Stream.of(existListener).forEach(rowPanel::addActionListener);
        }
        add(rowPanel, index.intValue());
        this.addBtn.setName(String.valueOf(this.rowPanelList.size()));
        updatePreferredSize();
    }

    private void updatePreferredSize(){
        Optional<Dimension> maxW = this.rowPanelList.stream().map(JPanel::getPreferredSize).max(Comparator.comparing(Dimension::getWidth));
        Optional<Dimension> maxH = this.rowPanelList.stream().map(JPanel::getPreferredSize).max(Comparator.comparing(Dimension::getHeight));
        int width = maxW.orElse(getPreferredSize()).width;
        int vgap = getLayout() instanceof FlowLayout?((FlowLayout)getLayout()).getVgap()*this.rowPanelList.size():0;
        int height = maxH.isPresent()?maxH.get().height*(this.rowPanelList.size()+1) + vgap:getPreferredSize().height;
        Dimension newPerferredSize = new Dimension(width, height);
        setPreferredSize(newPerferredSize);
        updateUI();
//        updateParentUI(newPerferredSize);
    }

    private void updateParentUI(Dimension newPerferredSize){
        Container parent = getParent();
        if(parent != null){
            parent.setPreferredSize(newPerferredSize);
            System.out.println("FacedPanel parent " + parent + "--newPerferredSize:" + parent.getPreferredSize());
            if(parent instanceof JComponent){
                System.out.println("is JComponent");
                ((JComponent) parent).updateUI();
                JComponent parentParent = (JComponent) parent.getParent();
                parent.getLayout().preferredLayoutSize(parentParent);
                parentParent.updateUI();
            }
        }
    }

    public void removeRow(Integer index){
        this.rowPanelList.remove(index.intValue());
        for (int i = 0; i < this.rowPanelList.size(); i++) {
            this.rowPanelList.get(i).setId(i);
        }
        remove(index.intValue());
        this.addBtn.setName(String.valueOf(this.rowPanelList.size()));
        updatePreferredSize();
    }

    public List<D> getData(){
        return this.rowPanelList.stream().map(RowPanel::getBindData).collect(Collectors.toList());
    }

    public D getSelectedData(){
        ButtonModel selection = this.buttonGroup.getSelection();
        if(selection != null){
            return this.rowPanelList.get(Integer.parseInt(selection.getActionCommand())).getBindData();
        }
        return null;
    }

    public String getSelectedID(){
        ButtonModel selection = this.buttonGroup.getSelection();
        if(selection != null){
            return selection.getActionCommand();
        }
        return null;
    }

    protected void addToPanel(){
        if(getComponentCount() > 0) {
            removeAll();
        }
        if(!this.rowPanelList.isEmpty()){
            this.rowPanelList.forEach(component -> {
                add(component, component.getId().intValue());
            });
        }
        this.addBtn.setName(String.valueOf(rowPanelList.size()));
        this.addBtn.addMouseListener(new AddAction(this.addBtn,this));
        add(this.addBtn);
        updatePreferredSize();
    }

    protected void addToPanel(List<Component> components){}

    public void addSelectActionListener(ActionListener listener){
        this.rowPanelList.forEach(row -> row.addActionListener(listener));
    }

    public void addSelectActionListener(Integer index, ActionListener listener){
        this.rowPanelList.get(index).addActionListener(listener);
    }

    class AddAction implements MouseListener {

        private final JButton relationBtn;
        private final FacedComponent<T,D> handler;

        public AddAction(JButton addBtn, FacedComponent<T,D> handler) {
            this.relationBtn = addBtn;
            this.handler = handler;
        }

        @Override
        public void mouseClicked(MouseEvent e) {

        }

        @Override
        public void mousePressed(MouseEvent e) {

        }

        @Override
        public void mouseReleased(MouseEvent e) {
            String id = relationBtn.getName();
            System.out.println("add id:" + id);
            handler.addRow(Integer.valueOf(id));
        }

        @Override
        public void mouseEntered(MouseEvent e) {

        }

        @Override
        public void mouseExited(MouseEvent e) {

        }
    }

}
